package es.uc3m.ce.practice1.ex5;


/** Adds 2 integer numbers introduced by the user in 2's complement and gives the result in this format.
 * @author Adrián Gil Moral - 100293146
 * @author Rafael Medina García - 100292314
 * */
public class AdditionComplement {

	/* <--- BEGIN 2'S COMPLEMENT TRANSFORMATION */
	
	/**
	 * Convert the decimal number into binary code. The algorithm will not take the sign into account
	 * @param integerNumber the number to calculate in binary code
	 * @param isNegative whether the sign should be taken into account or not
	 * @return Binary representation of the number regardless its sign
	 */
	private static String decimalToBinary(int integerNumber) {
		// Variables
		String binaryNumber = "";
		int temp = integerNumber;

		// If the number is 0, return 0
		if (integerNumber == 0) {
			return "0";
		}
		
		// Get rid of the sign (if any) and convert the number
		temp = Math.abs(temp);
		while (temp >= 1) {
			binaryNumber += temp % 2;
			temp = temp / 2;
		}

		// Reverse the order of the digits so the binary number is written
		// correctly
		String result = "";
		for (int i = binaryNumber.length() - 1; i >= 0; i--) {
			result += binaryNumber.charAt(i);
		}

		return result;
	}

	/**
	 * Calculate the 2's complement of a positive number
	 * @param binaryNumber the binary number to convert
	 * @return 2's complement representation of the given binary number
	 */
	private static String positiveToComp2(String binaryNumber) {
		String result = "";
		// As it is a positive number, enter 0 until the 32 bits are completed
		for (int i = 0; i < (32 - binaryNumber.length()); i++) {
			result += "0";
		}
		// Add all the 0s to the binary number that was already calculated
		result += binaryNumber;
		return result;
	}

	/**
	 * Calculate the 2's complement of a negative number
	 * @param binaryNumber the binary number to convert
	 * @return 2's complement representation of the given binary number
	 */
	private static String negativeToComp2(String binaryNumber) {
		String result = "";
		String negatedNumber = "";
		boolean negate = false;

		/* Negate the number accordingly */
		for (int i = binaryNumber.length() - 1; i >= 0; i--) {
			/* Did not find the first 1 yet */
			if (!negate) {
				// Number is 0
				if (binaryNumber.charAt(i) == '0') {
					// Add 0
					negatedNumber += "0";
				} else {
					// Add 1 and negate the following numbers
					negatedNumber += "1";
					negate = true;
				}
				/* Already found the first 1 */
			} else {
				if (binaryNumber.charAt(i) == '0') {
					// Negate the 0, add 1
					negatedNumber += "1";
				} else {
					// Negate the 1, add 0
					negatedNumber += "0";
				}
			}
		}

		// As it is a negative number, enter 1 until the 32 bits are completed
		for (int i = 0; i < (32 - binaryNumber.length()); i++) {
			result += "1";
		}
		// Add all the 1s to the negated number that was already calculated
		// (reversing the order)
		for (int i = negatedNumber.length() - 1; i >= 0; i--) {
			result += negatedNumber.charAt(i);
		}
		return result;
	}

	/**
	 * Calculate the 2's complement of a given integer number
	 * @param integerNumber the integer number to return in 2's complement representation
	 * @return 2's complement representation of the integer number
	 */
	public static String intToComp2(int integerNumber) {
		// Convert the number to binary code
		String binaryNumber = decimalToBinary(integerNumber);
		// Calculate the 2's complement representation accordingly
		if (integerNumber < 0) {
			return negativeToComp2(binaryNumber);
		}
		// Positive number
		return positiveToComp2(binaryNumber);
	}	
	
	/* END 2'S COMPLEMENT TRANSFORMATION ---> */
	
	/**
	 * Add the two numbers in 2's complement
	 * @param twoComp1 the first number to add
	 * @param twoComp2 the second number to add
	 * @return Result of the addition
	 */
	private static String addNumbers(String twoComp1, String twoComp2) {
		/* Add the numbers */
		boolean carry = false;
		String tempResult = "";
		String addResult = "";
		// Add from end to start
		for (int i = twoComp1.length() - 1 ; i >= 0; i--) {
			// NO CARRY
			if (!carry) {
				// Case 0 + 0
				if (twoComp1.charAt(i) == '0' && twoComp2.charAt(i) == '0') {
					tempResult += "0";
					carry = false;
				// Case 0 + 1	
				} else if (twoComp1.charAt(i) == '0' && twoComp2.charAt(i) == '1') {
					tempResult += "1";
					carry = false;
				// Case 1 + 0	
				} else if (twoComp1.charAt(i) == '1' && twoComp2.charAt(i) == '0') {
					tempResult += "1";
					carry = false;
				// Case 1 + 1	
				} else if (twoComp1.charAt(i) == '1' && twoComp2.charAt(i) == '1') {
					tempResult += "0";
					carry = true;
				}
			// CARRY	
			} else {
				// Case 0 + 0 + (1)
				if (twoComp1.charAt(i) == '0' && twoComp2.charAt(i) == '0') {
					tempResult += "1";
					carry = false;
				// Case 0 + 1 + (1)	
				} else if (twoComp1.charAt(i) == '0' && twoComp2.charAt(i) == '1') {
					tempResult += "0";
					carry = true;
				// Case 1 + 0 + (1)	
				} else if (twoComp1.charAt(i) == '1' && twoComp2.charAt(i) == '0') {
					tempResult += "0";
					carry = true;
				// Case 1 + 1 + (1)	
				} else if (twoComp1.charAt(i) == '1' && twoComp2.charAt(i) == '1') {
					tempResult += "1";
					carry = true;
				}
			}
		}
		// Reverse the order of the digits so the binary number is written correctly
		for (int i = tempResult.length() - 1; i >= 0; i--) {
			addResult += tempResult.charAt(i);
		}
		
		// Return the result of the addition
		return addResult;
	}
	
	/**
	 * Given two integer numbers, calculate the 2's complement representation and perform the addition.
	 * @param num1 the first integer number to transform into 2's complement and add
	 * @param num2 the second integer number to transform into 2's complement and add
	 * @return Result 2's complement addition
	 */
	public static String integerAdder(int num1, int num2) {
		/* Find the 2's complement of both numbers */
		String twoComp1 = intToComp2(num1);
		String twoComp2 = intToComp2(num2);
		
		/* Add the numbers */
		return addNumbers(twoComp1, twoComp2);
	}
	
	public static void main(String[] args) {
		System.out.println("2's complement of 13:");
		System.out.println(intToComp2(13));
		System.out.println("2's complement of 6:");
		System.out.println(intToComp2(6));
		System.out.println("Addition of 13 and 6:");
		System.out.println(integerAdder(13, 6));
	}

}
